package app

import (
	"github.com/pelletier/go-toml/v2"
	"github.com/pkg/errors"
	"kvmc/pkg/sshx"
	"kvmc/pkg/util"
	"os"
)

type Node struct {
	ClusterName string `toml:"-"`
	Name        string `toml:"name"`
	Hostname    string `toml:"hostname"`
	IP          string `toml:"ip"`
	Status      string `toml:"-"`
}

func (n *Node) IsRunning() bool {
	return n.Status == "running"
}

type Cluster struct {
	Name         string  `toml:"name"`
	Nodes        []*Node `toml:"nodes"`
	isSpreadName bool    `toml:"-"`
}

func (c *Cluster) GetNodes() []*Node {
	if !c.isSpreadName {
		for _, node := range c.Nodes {
			node.ClusterName = c.Name
		}
		c.isSpreadName = true
	}
	return c.Nodes
}

type Center struct {
	Addr       string `toml:"addr"`
	Username   string `toml:"username"`
	PrivateKey string `toml:"private_key"`
}

type Manager struct {
	Path           string              `toml:"-"`
	Center         *Center             `toml:"center"`
	DefaultCluster string              `toml:"default_cluster"`
	Clusters       map[string]*Cluster `toml:"clusters"`
}

func NewManager(filePath string) (*Manager, error) {
	m := &Manager{
		Path:           filePath,
		DefaultCluster: "default",
		Clusters:       make(map[string]*Cluster),
	}
	err := m.Load()
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (m *Manager) Load() error {
	if !util.IsFileExists(m.Path) {
		f, err := os.Create(m.Path)
		if err != nil {
			return err
		}
		defer f.Close()
		return nil
	}
	f, err := os.Open(m.Path)
	if err != nil {
		return err
	}
	defer f.Close()
	return toml.NewDecoder(f).Decode(m)
}

func (m *Manager) Save() error {
	f, err := os.Create(m.Path)
	if err != nil {
		return err
	}
	defer f.Close()
	return toml.NewEncoder(f).Encode(m)
}

func (m *Manager) GetCluster(clusterName string) *Cluster {
	if m.Clusters == nil {
		return nil
	}
	cluster := m.Clusters[clusterName]
	return cluster
}

func (m *Manager) GetClusterNodes(clusterName string) []*Node {
	if clusterName == "" {
		clusterName = m.DefaultCluster
	}
	if m.GetCluster(clusterName) == nil {
		return nil
	}
	nodes := m.Clusters[clusterName].GetNodes()
	return nodes
}

func (m *Manager) GetAllNodes() []*Node {
	nodes := make([]*Node, 0)
	for _, cluster := range m.Clusters {
		nodes = append(nodes, cluster.GetNodes()...)
	}
	return nodes
}

func (m *Manager) getCenterSSHClient() (*sshx.SShClient, error) {
	if m.Center == nil {
		return nil, errors.New("center is not set")
	}
	opt := &sshx.Option{
		Addr:       m.Center.Addr,
		Username:   m.Center.Username,
		PrivateKey: m.Center.PrivateKey,
	}
	client, err := sshx.NewSShClient(opt)
	if err != nil {
		return nil, err
	}
	return client, nil
}
